package com.wallace.downloadserver.netty

import com.wallace.downloadserver.netty.handler.inbound.NettyMsgDecryptHandler
import com.wallace.downloadserver.netty.handler.inbound.NettyMsgHandler
import com.wallace.downloadserver.netty.handler.outbound.NettyMsgEncryptHandler
import io.netty.bootstrap.ServerBootstrap
import io.netty.channel.*
import io.netty.channel.nio.NioEventLoopGroup
import io.netty.channel.socket.SocketChannel
import io.netty.channel.socket.nio.NioServerSocketChannel
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component

/**
1、ChannelOption.SO_BACKLOG  服务端处理客户端连接请求是顺序的，同一时间只能处理一个客户端连接，服务端将不能处理的连接放入指定大小的队列中
2、ChannelOption.TCP_NODELAY 是否禁止使用Nagle算法,该算法数据包大小没有达到时将等待其他数据
3、ChannelOption.SO_KEEPALIVE 设置该选项以后，如果在两小时内没有数据的通信时，TCP会自动发送一个活动探测数据报文
4、ChannelOption.SO_SNDBUF和ChannelOption.SO_RCVBUF 接收缓冲区和发送缓冲区的大小
5、RCVBUF_ALLOCATOR
FixedRecvByteBufAllocator 固定长度的接收缓冲区分配器，由它分配的ByteBuf长度都是固定大小的，并不会根据实际数据报的大小动态收缩。但是，如果容量不足，支持动态扩展
AdaptiveRecvByteBufAllocator 容量动态调整的接收缓冲区分配器，它会根据之前Channel接收到的数据报大小进行计算，如果连续填充满接收缓冲区的可写空间，则动态扩展容量。如果连续2次接收到的数据报都小于指定值，则收缩当前的容量，以节约内存
 */
@Component
class NettyServer {

    private val log: Logger = LoggerFactory.getLogger(NettyServer::class.java)

    var channel: Channel? = null

    @Autowired
    private var serverChannelInitializer: ServerChannelInitializer? = null

    fun start(port: Int) {
        log.info("正在启动Netty服务端...")
        // 创建两个线程组 boosGroup、workerGroup
        val bossGroup: EventLoopGroup = NioEventLoopGroup()
        val workerGroup: EventLoopGroup = NioEventLoopGroup()
        try {
            // 创建服务端的启动对象，设置参数
            val bootstrap = ServerBootstrap()
            // 设置两个线程组boosGroup和workerGroup
            bootstrap.group(bossGroup, workerGroup)
                    // 设置服务端通道实现类型
                    .channel(NioServerSocketChannel::class.java)
                    // 设置线程队列得到连接个数
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childHandler(serverChannelInitializer!!)
                    // 设置保持活动连接状态
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
            // 绑定端口号，启动服务端
            val channelFuture: ChannelFuture = bootstrap.bind(port).sync()
            if (channelFuture.isSuccess) {
                channel = channelFuture.channel()
                log.info("Netty服务端启动成功！")
            }
            // 对关闭通道进行监听
            channelFuture.channel().closeFuture().sync()
        } finally {
            bossGroup.shutdownGracefully()
            workerGroup.shutdownGracefully();
        }
    }
}